package input;

import java.util.logging.Logger;

import interfaces.hud.chat.ChatType;
import interfaces.hud.spectate.SpectateHUD;
import fileHandling.language.options.Controls;
import gameStates.absGamesStates.AbsIngameState;
import gameStates.absGamesStates.gui.AbsChatState;
import gameStates.absGamesStates.gui.AbsHUDState;
import gameStates.absGamesStates.gui.AbsSpawnState;
import main.InitGame;
import settings.ControlSettings;

import com.jme.input.controls.GameControl;
import com.jme.input.controls.controller.ActionChangeController;
import com.jme.input.controls.controller.ControlChangeListener;
import com.jme.scene.Node;

/**
 * Super-class for the {@link Player}s key-input. Provides key-bindings for opening the {@link SpawnMenu}, 
 * pausing the current {@link Game} and showing the {@link ScoreBoardState}.
 * 
 * @author Wasserleiche
 */
public class PlayerKeyInput extends NodeInputHandler {
	
	public static final Logger logger = Logger.getLogger("input.PlayerKeyInput");
	
	protected GameControl openSpawnMenu, scoreBoard, chat, teamChat, squadChat, showMap, pause, nextPlayer, prevPlayer;
	
	protected AbsChatState chatState;
	protected AbsSpawnState spawnState;
	protected AbsHUDState hudState;
	
	/**
	 * Constructs a new PlayerKeyInput-Object. All key-bindings and -actions will be initialized.
	 * @param rootNode The root-Node that will be used.
	 */
	public PlayerKeyInput(Node rootNode, AbsChatState chatState, AbsIngameState ingameState) {
		super(rootNode);
		this.chatState = chatState;
		this.spawnState = ingameState.getSpawnState();
		this.hudState = ingameState.getHUDState();
		
		setBindings();
		setActions();
		
		spawnState.addListenerToClearer(getChatListener());
	}
	
	/**
	 * Sets the key-bindings for opening the {@link SpawnMenu}, pausing and showing the 
	 * {@link ScoreBoardWindow}. The current {@link ControlSettings} will be used.
	 */
	private void setBindings() {
		openSpawnMenu = registerKeyControl(Controls.Spawn_Menu);
		scoreBoard = registerKeyControl(Controls.Scoreboard);
		
		chat = registerKeyControl(Controls.Chat);
		teamChat = registerKeyControl(Controls.Team_Chat);
		squadChat = registerKeyControl(Controls.Squad_Chat);

		showMap = registerKeyControl(Controls.Show_Map);
		
		pause = registerKeyControl(Controls.Pause);
		
		nextPlayer = registerKeyControl(Controls.Next_Player);
		prevPlayer = registerKeyControl(Controls.Prev_Player);
	}
	
	/**
	 * Sets the key-actions for all bindings.
	 */
	private void setActions() {
		ActionChangeController openSpawn = new ActionChangeController(openSpawnMenu, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(newValue == 1f && InitGame.get().isIngame()) InitGame.get().toggleSpawnMenu();
			}
		});
		rootNode.addController(openSpawn);
		
		ActionChangeController showPlayersWindow = new ActionChangeController(scoreBoard, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(InitGame.get().isIngame()) InitGame.get().toggleScoreBoard(newValue == 1f);
			}
		});
		rootNode.addController(showPlayersWindow);
		
		ActionChangeController startChat = new ActionChangeController(chat, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(newValue == 1f && !chatIsActive()) activateChat(ChatType.Chat);
			}
		});
		rootNode.addController(startChat);
		
		ActionChangeController startTeamChat = new ActionChangeController(teamChat, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(newValue == 1f && !chatIsActive()) activateChat(ChatType.TeamChat);
			}
		});
		rootNode.addController(startTeamChat);
		
		ActionChangeController startSquadChat = new ActionChangeController(squadChat, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(newValue == 1f && !chatIsActive()) activateChat(ChatType.SquadChat);
			}
		});
		rootNode.addController(startSquadChat);
		
		ActionChangeController showMapAction = new ActionChangeController(showMap, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(newValue == 1f && InitGame.get().isIngame()) {
					if(spawnState.isActive() && !spawnState.isShowingMiniMap()) {
						spawnState.showMiniMap();
						return;
					}
					spawnState.showMiniMap();
					InitGame.get().toggleSpawnMenu();
				}
			}
		});
		rootNode.addController(showMapAction);
		
		ActionChangeController pauseController = new ActionChangeController(pause, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
//				if(newValue == 1f) InitGame.get().togglePause();
			}
		});
		rootNode.addController(pauseController);
		
		ActionChangeController nextPlayerController = new ActionChangeController(nextPlayer, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(newValue == 1f && isSpectating()) hudState.nextPlayer(true);
			}
		});
		rootNode.addController(nextPlayerController);
		
		ActionChangeController prevPlayerController = new ActionChangeController(prevPlayer, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(newValue == 1f && isSpectating()) hudState.nextPlayer(false);
			}
		});
		rootNode.addController(prevPlayerController);
	}
	
	private boolean isSpectating() { return hudState.getCurrentHUD() instanceof SpectateHUD; }
	
	private void activateChat(ChatType type) {
		chatState.setActive(true);
		chatState.setChatType(type);
		
		InitGame.get().changeChatState(chatState);
	}
	
	private boolean chatIsActive() { return chatState.isActive(); }
}